﻿ /**
*	NetControl Track Network Map Viewer
* 	By Jie Gao, on May 2009, NetControl Project, UPRR
*
*/
import flash.display.Graphics;
import mx.controls. *;
import mx.controls.Label;
import mx.events.ItemClickEvent;
import mx.events.CloseEvent;
import mx.rpc.events.FaultEvent;
import mx.managers.PopUpManager;
import mx.containers.TitleWindow;
import com.esri.ags.geometry.Extent;
import com.esri.ags.events.MapEvent;
import com.esri.ags.events.LayerEvent;
import com.esri.ags.events.PanEvent;
import com.esri.ags.events.ZoomEvent;
import com.esri.ags.Graphic;
import com.esri.ags.symbol.Symbol;
import com.esri.ags.geometry.Geometry;
import com.esri.ags.geometry.Polygon;
import com.esri.ags.geometry.Polyline;
import mx.rpc.events.ResultEvent;
import com.esri.ags.layers.LayerInfo;
/*
import com.esri.maplib.TOC;
import com.esri.maplib.tocClasses.TocLayerInfoItem;
import com.esri.maplib.tocClasses.TocItem;
*/
import com.esri.ags.events.DrawEvent;
import com.esri.ags.events.IdentifyEvent;
import com.esri.ags.tasks.IdentifyParameters;
import com.esri.ags.tasks.IdentifyResult;
import com.esri.ags.toolbars.Draw;
import com.esri.ags.events.QueryEvent;
import com.esri.ags.tasks.FeatureSet;
import com.esri.ags.geometry.MapPoint;
import com.esri.ags.Map;
import com.esri.ags.utils.*;
import mx.collections.SortField;
import mx.collections.Sort;
import mx.collections.ArrayCollection;
import com.esri.ags.events.FindEvent;
import mx.core.IUIComponent;
import mx.events.DragEvent;
import mx.managers.DragManager;
import com.uprr.app.tnm.events.EventBus;
import com.uprr.app.tnm.events.AppEvent;
import com.uprr.app.tnm.model.Model;
import comp.LayerTOC;

import com.adobe.serialization.json.JSON;
import flash.net.URLRequest;

import mx.utils.ObjectUtil;

// default overlay map service, in the format mapServiceFolder/mapServiceName
 [Bindable]
private var defaultService : String;
// split to get rid of '/' for server communication via json parameters
 [Bindable]
private var mapServiceName : String;
// without folder
 [Bindable]
private var mapServiceFolder : String;
// without folder
// ESRI satellite imagery online service
 [Bindable]
private var satellitePath : String = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer";
 [Bindable]
// ESRI street map online service
private var streetPath : String = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer";
// overlay map service host, in the format: hostName:port#
 [Bindable]
private var host : String;
// overlay map service url, in the format:
// "http://" + host + "/arcgis/rest/services/" + defaultService + "/MapServer";
 [Bindable]
private var overlayMapUrl : String;



// not in use
 [Bindable]
//private var servicesPath : String = "http://" + host + "/arcgis/rest/services/";
private var servicesPath : String = "http://" + host + "/arcgis/services/";
private var theService : String;
private var newLayers : Boolean = false;
// for indentify result
 [Bindable]
private var infoData : Array;


//Initialization at loading
private function init () : void
{
	try {
	
	// no onlne service, goto basic viewer
	/*
	var u:URLRequest = new URLRequest("ncmap2.jsp");
	navigateToURL(u,"_self");	
	*/
	testEsriOnlineService(satellitePath);
	testEsriOnlineService(streetPath);
	
	//instance of EventBus;
	cursorManager.setBusyCursor ();
	map.alpha = 0.2;
	
	EventBus.addEventListener (AppEvent.MAP_EXTENT_UPDATE, updateMapExtent);
	EventBus.addEventListener (AppEvent.BASEMAP_ALPHA_CHANGE, changeBasemapOpacity);
	EventBus.addEventListener (AppEvent.REMOVE_GRAPHIC, removeGraphic);
	EventBus.addEventListener (AppEvent.MAPSVC_DOUBLECLICK, changeOverlayHandler);
	EventBus.addEventListener (AppEvent.BKMK_DOUBLECLICK, gotoBookmarkHandler);
	EventBus.addEventListener (AppEvent.TOC_DOUBLECLICK, changeActiveLayerHandler);
		
	//map.mapNavigationEnabled=false;
	//agsFolder.url = "http://" + host + "/arcgis/rest/services?f=json";
	//agsFolder.send ();
	//mapServiceCatalog.selectedIndex = 0;
	overlayMapLoader.url = "MapServiceQueryServlet";
	//var parameters:Object=new Object();
	//parameters.serviceKey="network";
	//overlayMapLoader.request=parameters;
	overlayMapLoader.send ();
	
	EventBus.addEventListener (AppEvent.APP_ERROR, showError);
	EventBus.addEventListener (AppEvent.NO_RESULTS, noResults);
	//EventBus.addEventListener (AppEvent.ADDRESS_FOUND, closeGeoLocatorWin);
	} catch (err:Error){
		var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
		errorEvent.data = "Error on initialization"+err.message;
		errorEvent.dispatch ();
	}
}


private function removeGraphic(event : AppEvent):void {
		var g:Graphic = event.data as Graphic; 
		graphicsLayer.remove(g);
}

/**
 * Handle TOC double click
 * @param	event
 */
private function changeActiveLayerHandler(event : AppEvent):void {
	try 
	{
		var layerId : int = event.data as int;
		var dropTarget : ComboBox = identifyLayer;
		for (var i : int = 0; i < dropTarget.dataProvider.length; i ++)
		{
			var obj : Object = dropTarget.dataProvider.getItemAt (i);
			if (obj.data == layerId)
			{
				identifyLayer.selectedItem = dropTarget.dataProvider.getItemAt (i);
				//infoLayerId = layerId;
				Model.getInstance ().infoLayerId = dropTarget.dataProvider.getItemAt (i).data;
				Model.getInstance ().infoLayerName = dropTarget.dataProvider.getItemAt (i).label;
				// update the query fields
				updateInfoLayerFields ();
				search.text = "";
				break;
			}
		}
	} catch (error : Error)
	{
		var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
		errorEvent.data = error.message;
		errorEvent.dispatch ();
	}
}


/**
 * Show Error
 * 
 * @usage   
 * @param   event 
 * @return  
 */

private function showError (event : AppEvent) : void
{
	
	// direct to erro page
	var u:URLRequest = new URLRequest("timeout.jsp");
	var variables:URLVariables = new URLVariables();
    variables.errorMessage = event.data as String;
    u.data = variables;
	navigateToURL(u,"_self");

	/*
	var errorWindow : ErrorWindow = ErrorWindow (PopUpManager.createPopUp (this, ErrorWindow, true));
	// Add title to the title bar.
	errorWindow.errorMessage = event.data as String;
	errorWindow.errorMessage=errorWindow.errorMessage+"\n\n Try close the browser and open a fresh browser window. If the error is persistent, please contact TNM team (402-544-1854). ";
	// Add a close button.
	// To close the container, your must also handle the close event.
	errorWindow.showCloseButton = true;
	*/
}


private function noResults (event : AppEvent) : void
{
	var errorWindow : ErrorWindow = ErrorWindow (PopUpManager.createPopUp (this, ErrorWindow, true));
	// Add title to the title bar.
	errorWindow.errorMessage = event.data as String;
	// To close the container, your must also handle the close event.
	errorWindow.showCloseButton = true;
}

// Load Overlay Map
/*
private function overlayMapLoaderHandler (event : ResultEvent) : void
{
	var rawData : String = String (event.result);
	var arr : Object = (JSON.decode (rawData) as Object);
	var uid : String = arr.uid;
	host = arr.hostName;
	defaultService = arr.mapServiceUrl;
	mapServiceFolder = arr.serviceFolder;
	mapServiceName = arr.serviceName;
	Model.getInstance ().overlayMapServiceFolder = arr.serviceFolder;
	Model.getInstance ().overlayMapServiceName = arr.serviceName;
	Model.getInstance ().overlayMapServiceHost = arr.hostName;
	overlayMapUrl = "http://" + host + "/arcgis/rest/services/" + defaultService + "/MapServer";
	//mapServiceCatalog.selectedItem = defaultService;
	overlayMap.url = overlayMapUrl;
	// initialize model
	Model.getInstance ().map = map;
	// get layer names
	layerNameLoader.url = overlayMapUrl + "?f=json";
	layerNameLoader.send ();
	// load map lagend
	mapLegendLoader.send ();
}
*/

private function overlayMapLoaderHandler (event : ResultEvent) : void
{
	
	try 
	{
		var rawData : String = String (event.result);
		
		var arr : Array = (JSON.decode (rawData) as Array);
		
		for (var i : int = 0; i < arr.length; i ++)
		{
		
			Model.getInstance ().serviceList.addItem ( 
			{
				name : arr [i].name, folder:arr [i].folder, hostName:arr[i].hostName, service:arr [i].service, id:arr[i].id, selected: (arr[i].selected=='Y') ? "ON" : ""
			} )
			
			
			if (arr[i].selected=='Y'){
				Model.getInstance ().overlayMapServiceFolder = arr[i].folder;
				Model.getInstance ().overlayMapServiceName = arr[i].service;
				Model.getInstance ().overlayMapServiceHost = arr[i].hostName;
				Model.getInstance ().overlayMapId=arr[i].id;
				
				var mapExtent:Object={minX:arr[i].minX,minY:arr[i].minY,maxX:arr[i].maxX,maxY:arr[i].maxY};
				var appEvent:AppEvent=new AppEvent(AppEvent.MAP_EXTENT_UPDATE);
				appEvent.data=mapExtent;
				appEvent.dispatch();
				
				var alpha:Object={alpha:arr[i].basemapAlpha}
				var appEvent2:AppEvent=new AppEvent(AppEvent.BASEMAP_ALPHA_CHANGE);
				appEvent2.data=alpha;
				appEvent2.dispatch();
				
				//Alert.show(arr[i].hostName+"/"+arr[i].folder+"/"+arr[i].service);
			}
			
			/*
			Model.getInstance ().serviceList.addItem ( 
			{name : arr [i].name, id:arr[i].id, selected: (arr[i].selected=='Y') ? "V" : ""} );
			var overlayMap:ArcGISDynamicMapServiceLayer=new ArcGISDynamicMapServiceLayer();
			overlayMap.url="http://" + host + "/arcgis/rest/services/" + arr [i].serviceUrl+ "/MapServer";
			overlayMap.id='overlaymap_'+i;
			overlayMap.addEventListener(MapEvent.LOAD, layerLoadCompleteHandler);
			if (arr[i].selected=='Y')
				overlayMap.visible=
			*/
		}
		
		
	} catch (err : Error)
	{
		var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
		errorEvent.data = "Error when adding bookmarks,"+err.message;
		errorEvent.dispatch ();
	}
	
	
	// init everything
	initMapViewer();
	
}

/**
 * Map viewer initialization
 * 
 * @usage   
 * @return  
 */
private var initFlag:Boolean=false;

private function initMapViewer():void{
 
	cursorManager.setBusyCursor ();
	host= Model.getInstance ().overlayMapServiceHost; 
	defaultService = Model.getInstance ().overlayMapServiceFolder+"/"+Model.getInstance ().overlayMapServiceName;
	// internal handler
	overlayMapUrl = "http://" + host + "/arcgis/rest/services/" + defaultService + "/MapServer";
	// external handler
	//overlayMapUrl = "http://" + host + "/arcgis/services/" + defaultService + "/MapServer";
	//Alert.show(overlayMapUrl);	
	overlayMap.url = overlayMapUrl;
	
	// initialize model
	Model.getInstance ().map = map;
	Model.getInstance ().graphicsLayer = graphicsLayer;
	// get layer names, use random num to disable clien caching
	var rnd : Number = Math.round(Math.random()*1000);
	layerNameLoader.url = overlayMapUrl + "?f=json&x="+rnd;
	
	//Alert.show(layerNameLoader.url );
	layerNameLoader.send ();
	
	// load map lagend
	mapLegendLoader.send ();
	
	// initial street-satellite alpha
	if (!initFlag){
		initFlag=true;
		var obj:Object={alpha:0.6};
		var alphaEvent : AppEvent = new AppEvent (AppEvent.BASEMAP_ALPHA_CHANGE);
		alphaEvent.data=obj;
		alphaEvent.dispatch();
	}
	

}

// street-satellite opacity change event
private function changeBasemapOpacity (event:AppEvent) : void
{
	var e:Object=event.data;
	Model.getInstance().mixerValue=e.alpha;
	street.alpha = 1 - e.alpha;
	satellite.alpha = e.alpha;

}

// when slider changed, update model value
private function changeAlphaMixer () : void
{
	 
	Model.getInstance().mixerValue=opacitySlider.value;
	//street.alpha = 1 - opacitySlider;
	//satellite.alpha = opacitySlider;
}

private function updateMapExtent(event:AppEvent):void{
	var e:Object=event.data;
	if (e.minX!=0){
		cursorManager.setBusyCursor ();
		map.alpha = 0.2;
		//Alert.show(e.minX+","+e.minY+","+e.maxX+","+e.maxY);		
		map.extent = new Extent ( e.minX,e.minY, e.maxX,e.maxY);
	}
		
	
}

private var mapToolId:Number = -1;
//Map Navigation Control ToolsBar Handler
private function itemClickHandler (event : ItemClickEvent) : void
{
	drawToolbar.deactivate ();
	doKml = false;
	mapToolId = -1;
	
	switch (event.index)
	{
		case 0 :
		{
			mapToolId = 0;
			navToolbar.activate (Navigation.ZOOM_IN);
			break;
		}
		case 1 :
		{
			mapToolId = 1;
			navToolbar.activate (Navigation.ZOOM_OUT);
			break;
		}
		case 2 :
		{
			mapToolId = 2;
			navToolbar.activate (Navigation.PAN);
			break;
		}
		case 3 :
		{
			mapToolId = 3;
			identifyToolHandler ();
			break;
		}
		/*
		case 4 :
		{
			// GE
			mapToolId = 4;
			showKml ();
			break;
		}
		*/
		case 4 :
		{
			// measure
			mapToolId = 4;
			drawToolbar.activate (Draw.POLYLINE);
			break;
		}
	}
}
private function identifyToolHandler () : void
{
	//drawToolbar.deactivate ();
	//graphicsLayer.clear ();
	drawToolbar.activate (Draw.MAPPOINT);
}
// full map extent map tool handler
private function toFullExt () : void
{
	cursorManager.setBusyCursor ();
	map.alpha = 0.2;
	map.extent = new Extent ( - 123.3, 21.29, - 87.48, 53.48);
}


// change overlay map handler
/*
private function changeOverlayMap (event : Event) : void
{
	//loadToc(host, theService);
	newLayers = true;
	theService = event.currentTarget.selectedItem as String;
	var sp:String="http://"+host+"/arcgis/rest/services/"+theService+"/MapServer";
	// internal handler
	//var sp : String = "http://" + host + "/arcgis/rest/services/TMS/TNM_Automated_GIS_Layers/MapServer";
	// external handler
	//var sp : String = "http://" + host + "/arcgis/services/TMS/TNM_Automated_GIS_Layers/MapServer";
	overlayMap.url = sp;
	cursorManager.setBusyCursor ();
}
*/


/**
* When the dynamic layer has been loaded
*/
private function layerLoadCompleteHandler () : void
{
	if (newLayers)
	{
		newLayers = false;
	}
	cursorManager.removeBusyCursor ();
	//map.mapNavigationEnabled=true;
	map.alpha = 1;
}

// when something goes wrong for all HTTP services
private function serviceFaultHandler (event : FaultEvent, sourceId : String ) : void
{
	//var evtSrcId:String=event.source.id;
	var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
	var folder : String = Model.getInstance ().overlayMapServiceFolder;
	var service : String = Model.getInstance ().overlayMapServiceName;
	var host : String = Model.getInstance ().overlayMapServiceHost;
	errorEvent.data = "Service Fault, source id:" + sourceId + "\n"
	+ "map service: " + host + "/" + folder + "/" + service+". "+event.fault.message;
	errorEvent.dispatch ();
}


// graphic layer symbol
private function symbolFunction (graphic : Graphic) : Symbol
{
	var result : Symbol;
	switch (graphic.geometry.type)
	{
		case Geometry.MAPPOINT :
		{
			result = smsIdentify;
			break;
		}
		case Geometry.POLYLINE :
		{
			result = slsIdentify;
			break;
		}
		case Geometry.POLYGON :
		{
			result = sfsIdentify;
			break;
		}
	}
	return result;
}
// IDENTIFY handlers
/**
* Activate the identify tool
*
* @usage
* @return
*/
private var identifyPoint : MapPoint;
private var xPoint : Geometry;
/**
* Identify tool handler, called when a draw action on map occurred.
*
* @usage
* @param   event
* @return
*/
private function identifyDrawEndHandler (event : DrawEvent) : void
{
	// map point for info window
	var graphic : Graphic;
	//if (mapToolId==3 || mapToolId==4){ // identify
	if (mapToolId==3 ){ // identify, without Google tool
	graphic = event.graphic;
	identifyPoint = graphic.geometry as MapPoint;
	var identifyParams : IdentifyParameters = new IdentifyParameters ();
	identifyParams.returnGeometry = true;
	identifyParams.tolerance = 3;
	identifyParams.width = map.width;
	identifyParams.height = map.height;
	identifyParams.geometry = graphic.geometry;
	var infoLayerId : int = Model.getInstance ().infoLayerId;
	identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_ALL + ":" + String (infoLayerId);
	//identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_ALL;
	identifyParams.mapExtent = map.extent;
	identifyTask.execute (identifyParams);
	//} else if (mapToolId == 5) { // measure
	} else if (mapToolId == 4) { // measure, without Google tool
		measureHandler(event.graphic); 
	}
	
}

// Measurement tool handler
private var disLoader:URLLoader;

private function measureHandler(g:Graphic):void            
{               		
 
	var geomStr:String=getGeometryJson(g);		
	if (g != null) {
			// for cleanup later
			Model.getInstance().graphicToRemove= g;
			disLoader = new URLLoader();
			var request:URLRequest = new URLRequest();
			request.method = URLRequestMethod.POST; 
			request.url="GetDistance";
			var variables:URLVariables = new URLVariables();
			variables.geometry = geomStr;		
			request.data=variables;
			disLoader.addEventListener(Event.COMPLETE, handleMeasureComplete);   
			disLoader.addEventListener(IOErrorEvent.IO_ERROR, onMeasureError);   
			disLoader.load(request);
	}
}

private function handleMeasureComplete(event : Event):void {
	var distStr:String = disLoader.data;
	Model.getInstance().distance = distStr;
	var distanceWin : DistanceWin = DistanceWin (PopUpManager.createPopUp (this, DistanceWin , true));
}

private function onMeasureError(event:IOErrorEvent):void {   
	var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
	errorEvent.data = "Error when calculating the distance.";
	errorEvent.dispatch ();
}  

 
/**
* Identify toolbar handler, called when when a draw action on map completed.
*
* @usage
* @param   event
* @return
*/
private function identifyCompleteHandler (event : IdentifyEvent) : void
{
	graphicsLayer.clear ();
	/**
	*  Restore search results if there is any
	*/
	showSearchResults ();
	infoData = new Array ();
	for each (var result : IdentifyResult in event.identifyResults)
	{
		var graphic : Graphic=null;
		try
		{
			graphic = result.feature;
			graphicsLayer.add (graphic);
			
			var obj : Object = graphic.attributes;
			var fld : String;
			var val : String;
			for (fld in obj)
			{
				val = obj [fld].toString ();
				
				// ignore 'SHAPE' & OBJECTID, etc
				if (fld.toUpperCase () !='SHAPE' && fld.toUpperCase () !='SHAPE.LEN' 
						&& fld.toUpperCase () !='OBJECTID' && fld.toUpperCase () !='SHAPE.LENGTH')
				
				infoData.push ( 
				{
					name : fld, value : val
				});
				
			}
			infoData.sortOn ('name');
			var data : DataGrid = new DataGrid ();
			data.dataProvider = infoData;
			data.width = 250;
			data.height = 180;
			//map.infoWindow.width=250;
			//map.infoWindow.height=180;
			map.infoWindow.label = "Feature Attributes";
			map.infoWindow.content = data;
			map.infoWindow.show (identifyPoint);
		} catch (error : Error)
		{
			var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
			errorEvent.data = "Identify Error: " + error.message;
			errorEvent.dispatch ();
		}
		// only one feature to return
		if (doKml==true && graphic !=null){
			//doKml=false;
			genKml(graphic, infoData);
		}
		
		break;
	}
}
/*
* Show search results if there there is any thing buffered.
* This is to make Identify and Search tools to work together, to
* keep search results when Identify erase previous highlights on map.
*
*/
private function showSearchResults () : void
{
	try 
	{
		/*
		*  No Search results
		*/
		var searchResultBuffer:ArrayCollection=Model.getInstance().searchResultBuffer;
		if (searchResultBuffer == null || searchResultBuffer.length==0)
		return;
		
		var resultCount : int = searchResultBuffer.length;
		
		if (resultCount > 0 )
		{
		
			/*
			*	why for (var obj:Object in searchResultBuffer)  does not work ???
			*/
			for (var i : Number = 0; i < resultCount; i ++)
			{
				var graphic : Graphic = searchResultBuffer [i] as Graphic;
				var tipText : String = "";
				var obj : Object = graphic.attributes;
				var fld : String;
				var val : String;
				for (fld in obj)
				{
					val = obj [fld].toString ();
					tipText = tipText + fld + ":" + val + "\n";
				}
				graphic.toolTip = tipText;
				switch (graphic.geometry.type)
				{
					case Geometry.MAPPOINT :
					graphic.symbol = sms;
					break;
					case Geometry.POLYLINE :
					graphic.symbol = sls;
					break;
					case Geometry.POLYGON :
					graphic.symbol = sfs;
					break;
				}
				graphicsLayer.add (graphic);
			}

		} 
		

		
	} catch (error : Error)
	{
		var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
		errorEvent.data = "Search Error: " + error.message;
		errorEvent.dispatch ();
	}
}
 
 

/*
*	layerNameLoader service results handler,
*   make sure to be called after map legend has been loaded
*
*/
private function getLayerNames (event : ResultEvent) : void
{
	var layerNames : Array = new Array ();
	var rawData : String = String (event.result);
	var obj : Object = (JSON.decode (rawData) as Object);
	var layers : Array = obj.layers;

	for (var i : int = 0; i < layers.length; i ++)
	{
		// only the layer, no folders
		if (layers [i].subLayerIds == null )
		{
			// layer symbol url
			//Alert.show(layers [i].id+":"+Model.getInstance ().layerIcons[layers [i].id]);
			layerNames.push ( 	
			//{label : layers [i].name, data : layers [i].id, iconUrl:Model.getInstance ().layerIcons[layers [i].id]}
			{label : layers [i].name, data : layers [i].id}
			)
		}
	}
	layerNames.sortOn ("label");
	// set the startup selection
	identifyLayer.selectedItem = layerNames [0];
	//infoLayerId = layerNames [0].data;
	Model.getInstance ().layerNames=layerNames;
	Model.getInstance ().infoLayerId = layerNames [0].data;
	Model.getInstance ().infoLayerName = layerNames [0].label;
	
	updateInfoLayerFields ();
}
// change info layer event handler
private function onChangeInfoLayer (event : Event) : void
{
	var infoLayerId : int = infoLayerId = event.currentTarget.selectedItem.data;
	/*
	layerFieldLoader.url = overlayMapUrl + "/" + infoLayerId + "?f=json";
	layerFieldLoader.send ();
	*/
	Model.getInstance ().infoLayerId = infoLayerId;
	Model.getInstance ().infoLayerName = event.currentTarget.selectedItem.label;
	updateInfoLayerFields ();
	search.text = "";
}
private function updateInfoLayerFields () : void
{
	var infoLayerId : int = Model.getInstance ().infoLayerId;
	layerFieldLoader.url = overlayMapUrl + "/" + infoLayerId + "?f=json";
	//Alert.show(queryTask.url);
	layerFieldLoader.send ();
}
/*
* layerFieldLoader service results handler
* called whenever the selected info layer changes
*/
private function getLayerFields (event : ResultEvent) : void
{
	var layerFields : Array = new Array ();
	var rawData : String = String (event.result);
	var obj : Object = (JSON.decode (rawData) as Object);
	var fields : Array = obj.fields;
	for (var i : int = 0; i < fields.length; i ++)
	{
		if (fields [i].type != 'esriFieldTypeOID' && fields [i].type != 'esriFieldTypeGeometry' 
		&& fields [i].name.toUpperCase () != 'SHAPE.Length' && fields [i].name.toUpperCase () !='SHAPE' 
		&& fields [i].name.toUpperCase () !='SHAPE.LEN' && fields [i].name.toUpperCase () !='OBJECTID')
		{
			layerFields.push (fields [i].name);
			//Alert.show(fields[i].name);
		}
	}
	
	Model.getInstance ().layerFields=layerFields;
}


// clear graphics event handler
private function doClear () : void
{
	try {
		search.text = "";
		graphicsLayer.clear ();
		Model.getInstance().searchResultBuffer.removeAll ();
	} catch (err:Error){
		var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
		errorEvent.data = "Error when cleaning grphics: " + err.message;
		errorEvent.dispatch ();
	}
}

// Query -- not in use
private function onQueryExecuteComplete (event : QueryEvent) : void
{
	//graphicsLayer.clear();
	infoData = new Array ();
	var fset : FeatureSet = event.featureSet;
	for each (var graphic : Graphic in fset.features)
	{
		try
		{
			graphicsLayer.add (graphic);
			var obj : Object = graphic.attributes;
			var fld : String;
			var val : String;
			for (fld in obj)
			{
				val = obj [fld].toString ();
				infoData.push ( 
				{
					name : fld, value : val
				});
			}
			var data : DataGrid = new DataGrid ();
			data.dataProvider = infoData;
			data.width = 250;
			data.height = 150;
			map.infoWindow.label = "Feature Attributes";
			map.infoWindow.content = data;
			map.infoWindow.show (identifyPoint);
		} catch (error : Error)
		{
			var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
			errorEvent.data = "Query Error: " + error.message;
			errorEvent.dispatch ();
		}
		//break;
	}
}

// Search
private function doSearch () : void
{
	map.alpha = 0.2;
	cursorManager.setBusyCursor ();
	var infoLayerId : int = Model.getInstance ().infoLayerId;
	searchParams.layerIds = [infoLayerId];
	//searchParams.searchFields = Model.getInstance ().layerFields;
	searchTask.execute (searchParams);
	/*
	Alert.show("layer is: "+infoLayerId+", field:"+Model.getInstance ().layerFields);
	Alert.show(searchTask.url);
	Alert.show(searchParams.searchText);
	*/
}

/**
 * Handle Search Results
 * 
 * @usage   
 * @param   event 
 * @return  
 */

private function searchCompleteHandler (event : FindEvent) : void
{
	try 
	{
		
		graphicsLayer.clear ();
		Model.getInstance().searchResultBuffer.removeAll();
		
		var graphic : Graphic;
		var resultCount : int = event.findResults.length;
		if (resultCount > 0 )
		{
			// to get the extent
			var graphics:Array=new Array();
			var searchResultBuffer:ArrayCollection = Model.getInstance().searchResultBuffer;
			
			// zoom to extent of all features      
			//GraphicUtil.getGraphicsExtent(graphics) has bugs when handling polygon
			//var unionedExtent:Extent = new Extent();    
			for (var i : Number = 0; i < resultCount; i ++)
			{
				graphic = event.findResults [i].feature;
				var tipText : String = "";
				var obj : Object = graphic.attributes;
				var fld : String;
				var val : String;
				for (fld in obj)
				{
					val = obj [fld].toString ();
					tipText = tipText + fld + ":" + val + "\n";
				}
				graphic.toolTip = tipText;
				switch (graphic.geometry.type)
				{
					case Geometry.MAPPOINT :
					graphic.symbol = sms;
					break;
					case Geometry.POLYLINE :
					graphic.symbol = sls;
					break;
					case Geometry.POLYGON :
					graphic.symbol = sfs;
					break;
				}
				graphicsLayer.add (graphic);
				var g : Object = graphic;
				searchResultBuffer.addItem(g);
				graphics.push(graphic);
				// extent
				//unionedExtent = unionedExtent.union(graphic.geometry.extent);	
			}
  
			// zoom to selected graphics
			var mapExtent:Extent=null;
			if (graphics.length>1) {
				mapExtent=GraphicUtil.getGraphicsExtent(graphics);
				//Alert.show(mapExtent.xmin+", map extent");
				map.extent=mapExtent.expand(1.2);
			} else if (graphics.length==1 && graphics[0].geometry.type==Geometry.MAPPOINT ){
				map.centerAt(graphics[0].geometry);
			} else if (graphics.length == 1 && graphics[0].geometry.type != Geometry.MAPPOINT ) {
				mapExtent = GraphicUtil.getGraphicsExtent(graphics);
				map.extent = mapExtent.expand(1.2);
			}
			
			//Alert.show(mapExtent.xmin+", map extent");
			//var appEvent:AppEvent=new AppEvent(AppEvent.MAP_EXTENT_UPDATE);
			//appEvent.data=mapExtent;
			//appEvent.dispatch();
			//map.extent = unionedExtent.expand(1.1); // zoom out a little                }
			//map.extent = new Extent ( - 123.3, 21.29, - 87.48, 53.48);
			//map.alpha = 0.2;
			//cursorManager.setBusyCursor ();
			
		} else
		{
			map.alpha = 1;
			cursorManager.removeBusyCursor ();
			var errorEvent : AppEvent = new AppEvent (AppEvent.NO_RESULTS);
			errorEvent.data = "No results were found within the specified data layer.";
			errorEvent.dispatch ();
		}
	} catch (error : Error)
	{
		map.alpha = 0.2;
		cursorManager.removeBusyCursor ();
		//var errorEvent:AppEvent=new AppEvent(AppEvent.APP_ERROR);
		errorEvent.data = "Search Error: " + error.message;
		errorEvent.dispatch ();
	}
}
/*
*  Map legend
*/
private function mapLegendLoaderHandler (event : ResultEvent) : void
{
	//cursorManager.setBusyCursor ();
	var layerIcons : Array = new Array ();
	//var layerIcons : ArrayCollection = new ArrayCollection ();
	var rawData : String = String (event.result);
	try 
	{
		var arr : Array = (JSON.decode (rawData) as Array);
		if (arr != null)
		{
			for (var i : int = 0; i < arr.length; i ++)
			{
				var layerName : String = arr [i].layerName as String;
				//Alert.show(layerName);
				var iconUrls : Array = arr [i].layerIconUrls as Array;
				var iconUrl : String = iconUrls [0] as String;
				var layerId : int = arr [i].layerId;
				//layerIcons.addItemAt(iconUrl,layerId);
				layerIcons[String (layerId)] = iconUrl;
		
			}
		}

	} catch (error : Error)
	{
		
		var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
		
		var stackTrace:String = ObjectUtil.toString(error.getStackTrace());
		var messageText:String = error.message;
		var errorName:String = error.name;
		var errorId:String = String(error.errorID);

		errorEvent.data = "Map Legend Error, name:" + errorName+", id:"+errorId+", message:"+messageText;
		errorEvent.dispatch ();
		
	}
	
		//test
		/*
		var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
		errorEvent.data = "Map Legend Error: this is a test to see how the error meesage looks like.";
		errorEvent.dispatch ();
		*/
		
		Model.getInstance ().layerIcons = layerIcons;
		layerToc.layer=overlayMap;
		cursorManager.removeBusyCursor ();
		
}


// bookmark & map service drag-drop
private function dragEnterMap (evt : DragEvent) : void
{
	var obj : IUIComponent = IUIComponent (evt.currentTarget);
	DragManager.acceptDragDrop (obj);
}

/**
 * @usage   
 * @param   evt 
 * @return  
 */

private function dragDropMap (evt : DragEvent) : void
{
	var itemsArray:Array=evt.dragSource.dataForFormat('items') as Array;
	var item:Object;
	
	try {
	if (itemsArray[0].service!=null){ // map service
		 item= svc.serviceList.selectedItem;
		var id:int = item.id;
		changeOverlayMap(id);
		
		/*
		for (var i:int=0; i<Model.getInstance ().serviceList .length; i++){
			if(id!=Model.getInstance ().serviceList .getItemAt(i).id)
				Model.getInstance ().serviceList .getItemAt(i).selected='';
			else
				Model.getInstance ().serviceList .getItemAt(i).selected='ON';
		}
		
 
		svc.serviceList.dataProvider.refresh();
		dispatchEvent(new Event("ServiceListUpdate"));
		
		Model.getInstance ().overlayMapServiceFolder = item.folder;
		Model.getInstance ().overlayMapServiceName = item.service;
		Model.getInstance ().overlayMapId = id;
		map.alpha = 0.2;
		//cursorManager.setBusyCursor ();
		initMapViewer();
		*/
			
	} else  if (itemsArray[0].bkmkId != null) { // bkmk
		 gotoBookmark();
		 /*
			item = bkmk.bkmkList.selectedItem;
			map.extent = new Extent (item.minX, item.minY, item.maxX, item.maxY);
		  */
	}
} catch (err:Error){
	// ignore if something goes wrong
	//Alert.show(err.toString());
}	
	
}

/**
 * Overlay datagrid double click handler
 * @param	evt
 */
private function changeOverlayHandler(evt:AppEvent):void {
	var oid:int = evt.data as int;
	changeOverlayMap(oid);
}


/**
 * Change overlay mpa handler
 * @param	mapServiceId
 */
private function changeOverlayMap(mapServiceId:int):void {
	try {
		var id:int = mapServiceId;		
		var item:Object;
		for (var i:int=0; i<Model.getInstance ().serviceList .length; i++){
			if(id!=Model.getInstance ().serviceList .getItemAt(i).id){
				Model.getInstance ().serviceList .getItemAt(i).selected = '';
			}else {
				item = Model.getInstance ().serviceList .getItemAt(i);	
				Model.getInstance ().serviceList .getItemAt(i).selected = 'ON';
			}
		}
		
		svc.serviceList.dataProvider.refresh();
		dispatchEvent(new Event("ServiceListUpdate"));
		
		Model.getInstance ().overlayMapServiceFolder = item.folder;
		Model.getInstance ().overlayMapServiceName = item.service;
		Model.getInstance ().overlayMapId = id;
		map.alpha = 0.2;
		//cursorManager.setBusyCursor ();
		initMapViewer();
	} catch (err:Error){
		// ignore if something goes wrong
		//Alert.show(err.toString());
	}
}

private function gotoBookmarkHandler(evt:AppEvent):void {
	gotoBookmark();
}

/**
 *  handle bookmark selection
 */
private function gotoBookmark():void {
			var item:Object = bkmk.bkmkList.selectedItem;
			map.extent = new Extent (item.minX, item.minY, item.maxX, item.maxY);
}


// search layer drag drop
private function layer_dragEnter (evt : DragEvent) : void
{
	var obj : IUIComponent = IUIComponent (evt.currentTarget);
	DragManager.acceptDragDrop (obj);
}

/**
 * Layer Drop
 * 
 * @usage   
 * @param   evt 
 * @return  
 */

private function layer_dragDrop (evt : DragEvent) : void
{
	try 
	{
		var dragObj : Array = evt.dragSource.dataForFormat ("items") as Array;
		//var layerName:String=dragObj[0].name;
		var layerId : int = dragObj [0].id;
		var dropTarget : ComboBox = ComboBox (evt.currentTarget);
		for (var i : int = 0; i < dropTarget.dataProvider.length; i ++)
		{
			var obj : Object = dropTarget.dataProvider.getItemAt (i);
			if (obj.data == layerId)
			{
				identifyLayer.selectedItem = dropTarget.dataProvider.getItemAt (i);
				//infoLayerId = layerId;
				Model.getInstance ().infoLayerId = dropTarget.dataProvider.getItemAt (i).data;
				Model.getInstance ().infoLayerName = dropTarget.dataProvider.getItemAt (i).label;
				// update the query fields
				updateInfoLayerFields ();
				search.text = "";
				break;
			}
		}
	} catch (error : Error)
	{
		var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
		errorEvent.data = error.message;
		errorEvent.dispatch ();
	}
}




private function doSnapShot(event:Event):void {
	Alert.show("The current map view has been saved as default");
}

private function showSnapshotWin () : void
{
	var setDefaultMapWin : SetDefaultMapWin = SetDefaultMapWin (PopUpManager.createPopUp (this, SetDefaultMapWin , true));

}

private function showHelpWin () : void
{
	var setHelpWin : SetHelpWin = SetHelpWin (PopUpManager.createPopUp (this, SetHelpWin , true));
	 
}

 
private function showGeoLocatorWin () : void
{
	var geoLocatorWin:GeoLocatorWin= GeoLocatorWin (PopUpManager.createPopUp (this,GeoLocatorWin , true));
	 
}


// activate Kmlgen 
private function showKml():void {	
	 //drawToolbar.deactivate();
	 //Alert.show('KML is activated');
	 drawToolbar.activate (Draw.MAPPOINT);
	 doKml=true;
}

/**
* KML tool 
* 
* -- TODO, pass attributes to show on GE
* 
*/
import flash.net.*;
private var doKml:Boolean=false;

private function genKml(g:Graphic, infoData:Array):void            
{               		
 
	var type:String=g.geometry.type;
	var geomStr:String=getGeometryJson(g);	
	
	if (type!=null && geomStr!=null){
			var loader:URLLoader = new URLLoader();
			var request:URLRequest = new URLRequest();
			request.method = URLRequestMethod.POST; 
			request.url="UploadGraphicServlet";
			var variables:URLVariables = new URLVariables();
			variables.type=type;
			variables.geometry = geomStr;
			variables.layer = Model.getInstance().infoLayerName;
		
			// feature attributes
			/*
			infoData = new Array ();
			var obj : Object = g.attributes;
			var fld : String;
			var val : String;
			for (fld in obj)
			
			{
				val = obj [fld].toString ();
				// ignore 'SHAPE' & OBJECTID, etc
				if (fld.toUpperCase () !='SHAPE' && fld.toUpperCase () !='SHAPE.LEN' 
						&& fld.toUpperCase () !='OBJECTID' && fld.toUpperCase () !='SHAPE.LENGTH')
				
				infoData.push ( 
				{
					name : fld, value : val
				});
				
			}
			*/
			var jsonStr:String = JSON.encode(infoData);
			variables.attrib = jsonStr;
			// end of attr
			
			request.data=variables;
			loader.addEventListener(Event.COMPLETE, handleKmlComplete);   
			loader.addEventListener(IOErrorEvent.IO_ERROR, onKmlIOError);   
			loader.load(request);
	}
           
}

private function handleKmlComplete(event:Event):void {   
			var u:URLRequest = new URLRequest("kmlgen.kml");
			navigateToURL(u,"_blank");
}

private function onKmlIOError(event:IOErrorEvent):void {   
	// chnage to use APP.ERROR
	var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
	errorEvent.data = "The feature geometry is too big to upload.";
	errorEvent.dispatch ();
}   


	/*
			var u:URLRequest = new URLRequest("kmlgen.kml?type="+type+"&geometry="+geomStr);
			navigateToURL(u,"_blank");
			*/
			
/**
 * Get geometry json string from graphic to communicate with server.
 * 
 * @usage   
 * @param   g 
 * @return  
 */

private function getGeometryJson(g:Graphic):String{
	
	var geom:Geometry=g.geometry;
	var type:String=geom.type;
	var jsonString:String=null;
	
	switch (type)
	{
		case "esriGeometryPoint" :
		{
			var pt:MapPoint=geom as MapPoint;
			var p:Object={x:pt.x, y:pt.y};
			jsonString=JSON.encode(p);
			break;
		}
		case "esriGeometryPolyline":
		{
			var line:Polyline=geom as Polyline;
			var arr:Array=line.paths;
			var pathArray:Array=new Array();
			for (var i:int=0; i<arr.length; i++){
				var pntArray:Array=new Array();
				var paths:Array=arr[i] as Array;
				for (var j:int=0; j<paths.length; j++){
					var mapPoint:MapPoint=paths[j] as MapPoint;
					pntArray.push({x:mapPoint.x, y:mapPoint.y});
				}
				pathArray.push({path:pntArray});
			}
			
			var polyline:Object={paths:pathArray}
			jsonString=JSON.encode(polyline);
			break;
		}
		case "esriGeometryPolygon":
		{
			var polygon:Polygon=geom as Polygon;
			var arr2:Array=polygon.rings;
			var pathArray2:Array=new Array();
			for (var i2:int=0; i2<arr2.length; i2++){
				var pntArray2:Array=new Array();
				var paths2:Array=arr2[i2] as Array;
				for (var j2:int=0; j2<paths2.length; j2++){
					var mapPoint2:MapPoint=paths2[j2] as MapPoint;
					pntArray2.push({x:mapPoint2.x, y:mapPoint2.y});
				}
				pathArray2.push({path:pntArray2});
			}
			
			var area:Object={paths:pathArray2}
			jsonString=JSON.encode(area);
			break;
		}
 
	}
	
	return jsonString;
}


/*
*	Test to see of ESRI on;ine service is availiable 
*/
private function testEsriOnlineService(url:String):void {
	
	var httpRequest:HTTPService =new HTTPService();
		httpRequest.url=satellitePath;
		var parameters:Object=new Object();
		parameters.f="json";

		httpRequest.request=parameters;
		httpRequest.resultFormat="text";
		httpRequest.addEventListener(ResultEvent.RESULT, getEsriOnlineServiceResultHandler);
		httpRequest.addEventListener("fault", getEsriOnlineServiceFaultHandler);
		httpRequest.send();
}


private function getEsriOnlineServiceResultHandler(event : ResultEvent):void {
	try 
	{
		var rawData : String = String (event.result);
	
		var obj : Object = (JSON.decode (rawData) as Object);
		if (obj.serviceDescription==null){
			 	var u:URLRequest = new URLRequest("ncmap2.jsp");
				navigateToURL(u,"_self");	
		}
	 
	} catch (err : Error)
	{
		var errorEvent : AppEvent = new AppEvent (AppEvent.APP_ERROR);
		errorEvent.data = "Error when adding bookmarks,"+err.message;
		errorEvent.dispatch ();
	}
	 
}

// when something goes wrong for all HTTP services
private function getEsriOnlineServiceFaultHandler (event : Event) : void
{
	var u:URLRequest = new URLRequest("ncmap2.jsp");
	navigateToURL(u,"_self");	
	
}



